//
//	(c) 2009 Andrew Kalmacky
//

#ifndef _AK_DOM_TYPES_H_
#define _AK_DOM_TYPES_H_

#include "../logger/logger.h"
#include "dom_abstracts.h"
#include "../stdint.h"
#include "../ltm/ltm_vector.h"
#include "../ltm/master_vector.h"
#include <limits>

namespace ak { namespace dom
{
	using ak::ltm::weak;
	using ak::ltm::vector;
	using ak::ltm::master_vector;

	struct DomLogSystem{};
	typedef Log::Logger<DomLogSystem, Log::lv_Default> log;

	class IntType: public Type
	{
		friend class EnumType;
	public:
		IntType(const pin<TypeName>& name);
		virtual TypeId get_type_id() const;
		virtual bool is_int_signed() const;
		virtual void destruct(void* ptr) const;
	};

	class I8Type: public IntType
	{
	public:
		I8Type(const pin<TypeName>& name);
		virtual size_t get_instance_size() const;
		virtual int read_int(void* ptr) const;
		virtual long64 read_long64(void* ptr) const;
		virtual void write_int(void* ptr, int val) const;
		virtual void write_long64(void* ptr, long64 val) const;
		virtual void construct(void* ptr) const;
		virtual void copy(void* dst_ptr, void* src_ptr) const;
	};
	class U8Type: public I8Type
	{
	public:
		U8Type(const pin<TypeName>& name);
		virtual int read_int(void* ptr) const;
		virtual long64 read_long64(void* ptr) const;
		virtual void write_int(void* ptr, int val) const;
		virtual void write_long64(void* ptr, long64 val) const;
		virtual bool is_int_signed() const;
	};

	class I16Type: public IntType
	{
	public:
		I16Type(const pin<TypeName>& name);
		virtual size_t get_instance_size() const;
		virtual int read_int(void* ptr) const;
		virtual long64 read_long64(void* ptr) const;
		virtual void write_int(void* ptr, int val) const;
		virtual void write_long64(void* ptr, long64 val) const;
		virtual void construct(void* ptr) const;
		virtual void copy(void* dst_ptr, void* src_ptr) const;
	};
	class U16Type: public I16Type
	{
	public:
		U16Type(const pin<TypeName>& name);
		virtual int read_int(void* ptr) const;
		virtual long64 read_long64(void* ptr) const;
		virtual void write_int(void* ptr, int val) const;
		virtual void write_long64(void* ptr, long64 val) const;
		virtual bool is_int_signed() const;
	};

	class I32Type: public IntType
	{
	public:
		I32Type(const pin<TypeName>& name);
		virtual size_t get_instance_size() const;
		virtual int read_int(void* ptr) const;
		virtual long64 read_long64(void* ptr) const;
		virtual void write_int(void* ptr, int val) const;
		virtual void write_long64(void* ptr, long64 val) const;
		virtual void construct(void* ptr) const;
		virtual void copy(void* dst_ptr, void* src_ptr) const;
	};
	class U32Type: public I32Type
	{
	public:
		U32Type(const pin<TypeName>& name);
		virtual int read_int(void* ptr) const;
		virtual long64 read_long64(void* ptr) const;
		virtual void write_int(void* ptr, int val) const;
		virtual void write_long64(void* ptr, long64 val) const;
		virtual bool is_int_signed() const;
	};

	class I64Type: public IntType
	{
	public:
		I64Type(const pin<TypeName>& name);
		virtual size_t get_instance_size() const;
		virtual int read_int(void* ptr) const;
		virtual long64 read_long64(void* ptr) const;
		virtual void write_int(void* ptr, int val) const;
		virtual void write_long64(void* ptr, long64 val) const;
		virtual void construct(void* ptr) const;
		virtual void copy(void* dst_ptr, void* src_ptr) const;
	};

	class U64Type: public I64Type
	{
	public:
		U64Type(const pin<TypeName>& name);
		virtual int read_int(void* ptr) const;
		virtual long64 read_long64(void* ptr) const;
		virtual void write_int(void* ptr, int val) const;
		virtual void write_long64(void* ptr, long64 val) const;
		virtual bool is_int_signed() const;
	};

	class FloatType: public Type
	{
	public:
		FloatType(const pin<TypeName>& name);
		virtual TypeId get_type_id() const;
		virtual size_t get_instance_size() const;
		virtual size_t get_float_m_width() const;
		virtual size_t get_float_p_width() const;
		virtual double read_double(void* ptr) const;
		virtual void write_double(void* ptr, double val) const;
		virtual void construct(void* ptr) const;
		virtual void destruct(void* ptr) const;
		virtual void copy(void* dst_ptr, void* src_ptr) const;
	};

	class DoubleType: public Type
	{
	public:
		DoubleType(const pin<TypeName>& name);
		virtual TypeId get_type_id() const;
		virtual size_t get_instance_size() const;
		virtual size_t get_float_m_width() const;
		virtual size_t get_float_p_width() const;
		virtual double read_double(void* ptr) const;
		virtual void write_double(void* ptr, double val) const;
		virtual void construct(void* ptr) const;
		virtual void destruct(void* ptr) const;
		virtual void copy(void* dst_ptr, void* src_ptr) const;
	};

	class EnumType: public Type
	{
		master<Type> base_type;
		master_vector<EnumTag> tags;
	public:
		EnumType(const pin<TypeName>& name, const pin<Type>& base_type, const std::list<string>& tags);
		virtual TypeId get_type_id() const;
		virtual size_t get_instance_size() const;
		virtual pin<EnumTag> read_tag(void* ptr) const;
		virtual void write_tag(void* ptr, const pin<EnumTag>& val) const;
		virtual size_t get_enum_tags_count() const;
		virtual pin<EnumTag> get_enum_tag(size_t index) const;
		virtual void construct(void* ptr) const;
		virtual void destruct(void* ptr) const;
		virtual void copy(void* dst_ptr, void* src_ptr) const;;
	};

	class StringType: public Type
	{
	public:
		StringType(const pin<TypeName>& name);
		virtual TypeId get_type_id() const;
		virtual size_t get_instance_size() const;
		virtual string read_string(void* ptr) const;
		virtual void write_string(void* ptr, const string& val) const;
		virtual void construct(void* ptr) const;
		virtual void destruct(void* ptr) const;
		virtual void copy(void* dst_ptr, void* src_ptr) const;
	};

	class MasterPtrType: public Type
	{
	public:
		MasterPtrType(const pin<TypeName>& name);
		virtual TypeId get_type_id() const;
		virtual size_t get_instance_size() const;
		virtual void construct(void* ptr) const;
		virtual void destruct(void* ptr) const;
		virtual void copy(void* dst_ptr, void* src_ptr) const;
		virtual pin<Node> read_ptr(void* ptr) const;
		virtual void write_ptr(void* ptr, const pin<Node>& val) const;
	};

	class WeakPtrType: public Type
	{
	public:
		WeakPtrType(const pin<TypeName>& name);
		virtual TypeId get_type_id() const;
		virtual size_t get_instance_size() const;
		virtual void construct(void* ptr) const;
		virtual void destruct(void* ptr) const;
		virtual void copy(void* dst_ptr, void* src_ptr) const;
		virtual pin<Node> read_ptr(void* ptr) const;
		virtual void write_ptr(void* ptr, const pin<Node>& val) const;
	};

	class StaticArrayType: public Type
	{
		master<Type> items_type;
		size_t size;
		StaticArrayType(const pin<TypeName>& name, const pin<Type>& items_type, size_t size);
		virtual size_t get_instance_size() const;
		virtual TypeId get_type_id() const;
		virtual size_t get_vector_items_count() const;
		virtual pin<Type> get_vector_items_type() const;
		virtual void construct(void* ptr) const;
		virtual void destruct(void* ptr) const;
		virtual void copy(void* dst_ptr, void* src_ptr) const;
		virtual size_t read_items_count(void* ptr) const;
		virtual void* read_item_offset(void* ptr, size_t index) const;
	};

	template<typename T>
	class LtmVectorType: public Type
	{
		master<Type> items_type;

		LtmVectorType(const pin<TypeName>& name, const pin<Type>& items_type)
			: Type(name)
			, items_type(items_type) // it should be a proper descriptor of item type in current domain
		{}
		virtual size_t get_instance_size() const { return sizeof ltm_vector_type<T>; }
		virtual TypeId get_type_id() const { return TYPE_VECTOR; }
		virtual size_t get_vector_items_count() const { return 0; }
		virtual pin<Type> get_vector_items_type() const { return items_type; }

		virtual void construct(void* ptr) const { new(ptr) vector<T>; }
		virtual void destruct(void* ptr) const
		{
			ptr->vector<T>::~vector<T>();
		}
		virtual void copy(void* dst_ptr, void* src_ptr) const
		{
			new (dst_ptr) vector<T>(*(vector<T>*)src_ptr);
		}
		virtual size_t read_items_count(void* ptr) const { return ((vector<T>*)ptr)->size(); }
		virtual void* read_item_offset(void* ptr, size_t index) const { return &((vector<T>*)ptr)->at(index);}
		virtual void insert_items(void* ptr, size_t index, size_t count) const
		{
			vector<T>& v = *(vector<T>*)ptr;
			v.insert_range(index, count);
		}
		virtual void delete_items(void* ptr, size_t index, size_t count) const
		{
			vector<T>& v = *(vector<T>*)ptr;
			v.erase(v.begin() + index, v.begin() + index + count);
		}
	};
}}

#endif // _AK_DOM_TYPES_H_
